﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace FezLogForSns
{
    class LogConverter
    {
        private Constant.ConvertError error = Constant.ConvertError.None;

        private string result = "";

        public Dictionary<string, bool> CheckStatus;

        public Dictionary<string, bool> CheckBold;

        public Dictionary<string, bool> CheckItalic;

        public Dictionary<string, string> ColorCode;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="checks"></param>
        /// <param name="bolds"></param>
        /// <param name="italics"></param>
        /// <param name="colors"></param>
        public LogConverter(Dictionary<string, bool> checks, Dictionary<string, bool> bolds, Dictionary<string, bool> italics, Dictionary<string, string> colors)
        {
            setConfig(checks, bolds, italics, colors);
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="conf"></param>
        public LogConverter(AppConfig conf)
        {
            setConfig(conf);
        }

        /// <summary>
        /// 設定
        /// </summary>
        /// <param name="conf"></param>
        /// <returns></returns>
        public LogConverter setConfig(AppConfig conf)
        {
            return setConfig(conf.checkStatus, conf.checkBold, conf.checkItalic, conf.colorCode);
        }

        /// <summary>
        /// 設定
        /// </summary>
        /// <param name="checks"></param>
        /// <param name="bolds"></param>
        /// <param name="italics"></param>
        /// <param name="colors"></param>
        /// <returns></returns>
        public LogConverter setConfig(Dictionary<string, bool> checks, Dictionary<string, bool> bolds, Dictionary<string, bool> italics, Dictionary<string, string> colors)
        {
            CheckStatus = checks;
            CheckBold = bolds;
            CheckItalic = italics;
            ColorCode = colors;
            return this;
        }

        /// <summary>
        /// エラー列挙体の取得
        /// </summary>
        /// <returns></returns>
        public Constant.ConvertError getError()
        {
            return error;
        }

        /// <summary>
        /// 変換結果を取得
        /// </summary>
        /// <returns></returns>
        public string getResult()
        {
            return result;
        }

        /// <summary>
        /// 処理の実行
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool run(string data)
        {
            this.result = "";
            error = Constant.ConvertError.None;

            // 変換処理
            data = parseBody(data);
            StringReader sr = new StringReader(data);
            
            string line;
            data = "";
            while ((line = sr.ReadLine()) != null)
            {
                line = convertLine(line);
                if (line.Length == 0)
                {
                    continue;
                }

                data += line + Environment.NewLine;
            }

            if (data.Length == 0)
            {
                error = Constant.ConvertError.ConvertEmpty;
                return false;
            }

            this.result = data;
            return true;
        }

        /// <summary>
        /// Body要素の中身のみ取り出します
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string parseBody(string data)
        {
            Regex reg = new Regex("^.*<body[^>]*>(.*)</body>.*$",
                RegexOptions.IgnoreCase | RegexOptions.Singleline);

            if(!reg.IsMatch(data))return data;

            Match mc = reg.Match(data);

            return mc.Groups[1].Value;
        }

        /// <summary>
        /// HTMLエスケープされた文字を戻す
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string decodeHtml(string data)
        {
            return data
                .Replace("&quot;", "\"").Replace("&quot", "\"")
                .Replace("&lt;", "<").Replace("&lt", "<")
                .Replace("&gt;", ">").Replace("&gt", ">")
                .Replace("&amp;", "&")
                ;
        }

        /// <summary>
        /// 行ごとに変換を行う
        /// </summary>
        /// <param name="Line"></param>
        /// <returns></returns>
        private string convertLine(string Line)
        {
            Line = Line.Trim();
            if (Line.Length == 0) return Line;

            Regex reg;
            string[] range = Constant.Range;

            foreach (string type in range)
            {
                reg = new Regex("<div class=\"" + type + "\">(.*)</div>", RegexOptions.IgnoreCase);
                if (!reg.IsMatch(Line)) continue;

                if (!CheckStatus[type]) return "";

                Match mc = reg.Match(Line);
                Line = mc.Groups[1].Value;
                Line = Line.Replace("  ", "　");
                Line = decodeHtml(Line);

                if (ColorCode[type] != "000000")
                {
                    Line = "<op:color code=\"#" + ColorCode[type] + "\">" + Line + "</op:color>";
                }

                if (CheckBold[type])
                {
                    Line = "<op:b>" + Line + "</op:b>";
                }

                if (CheckItalic[type])
                {
                    Line = "<op:i>" + Line + "</op:i>";
                }

                return Line;
            }

            // その他のシステムメッセージの場合
            string[] others = { "battle_friend", "battle_enemy", "battle_etc", "attack", "defence", };
            
            foreach (string other in others)
            {
                reg = new Regex("<div class=\"" + other + "\">(.*)</div>", RegexOptions.IgnoreCase);
                if (!reg.IsMatch(Line)) continue;

                if (!CheckStatus["system"]) return "";

                Match mc = reg.Match(Line);
                Line = mc.Groups[1].Value;
                Line = Line.Replace("  ", "　");
                Line = decodeHtml(Line);

                if (ColorCode["system"] == "000000")
                {
                    Line = "<op:color code=\"#" + ColorCode["system"] + "\">" + Line + "</op:color>";
                }

                if (CheckBold["system"])
                {
                    Line = "<op:b>" + Line + "</op:b>";
                }

                if (CheckItalic["system"])
                {
                    Line = "<op:i>" + Line + "</op:i>";
                }

                return Line;
            }

            // いずれにも当てはまらない場合
            Line = Line.Replace("  ", "　");
            Line = decodeHtml(Line);
            return Line;
        }
    }
}
